//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.splic.common.gen;

import java.util.Calendar;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.Assert;

public class DistributedRidesLock {
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    private static final String separator = ",";
    private StringRedisTemplate stringRedisTemplate;
    private String lockPrefix;

    public DistributedRidesLock(StringRedisTemplate stringRedisTemplate, String lockPrefix) {
        this.stringRedisTemplate = stringRedisTemplate;
        this.lockPrefix = lockPrefix;
    }

    public String lock(String bizCacheKey, int expireSeconds) {
        return this.lock(bizCacheKey, expireSeconds, false);
    }

    public String lock(String bizCacheKey, int expireSeconds, boolean lockFailureAssert) {
        return this.lock(bizCacheKey, expireSeconds, 0, 0, lockFailureAssert);
    }

    public String lock(String bizCacheKey, int expireSeconds, int retryCount, boolean lockFailureAssert) {
        return this.lock(bizCacheKey, expireSeconds, retryCount, 100, lockFailureAssert);
    }

    public String lock(String bizCacheKey, int expireSeconds, int retryCount, int retryIntervalMilliscond, boolean lockFailureAssert) {
        String lockUniqueId = null;

        do {
            lockUniqueId = this.locked(bizCacheKey, expireSeconds);
            if (null != lockUniqueId) {
                return lockUniqueId;
            }

            --retryCount;
            if (retryCount > 0) {
                Assert.isTrue(retryIntervalMilliscond > 0, "retryIntervalMilliscond must be > 0 !");

                try {
                    Thread.currentThread();
                    Thread.sleep((long)retryIntervalMilliscond);
                } catch (InterruptedException var8) {
                    this.logger.error("lock retry , sleep error !");
                }
            }
        } while(retryCount > 0);

        if (lockFailureAssert) {
            Assert.hasText(lockUniqueId, "[lock error]There are other threads executing, please try again later!");
        }

        return lockUniqueId;
    }

    public void unlock(String lockKey, String uniqueId) {
        String key = this.lockPrefix + String.format(":DistributedLock:%s", lockKey);
        String currentValue = (String)this.stringRedisTemplate.opsForValue().get(key);
        if (null != currentValue) {
            Assert.isTrue(StringUtils.contains(currentValue, ",") && currentValue.split(",")[1].equals(uniqueId), "[unlock error] lockKey: " + key + " , uniqueId :" + uniqueId);
            this.stringRedisTemplate.delete(key);
        }

        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Business unlock：{}", key);
        }

    }

    private String locked(String bizCacheKey, int expireSeconds) {
        String lockKey = this.lockPrefix + String.format(":DistributedLock:%s", bizCacheKey);
        String uniqueId = UUID.randomUUID().toString();
        String lockValue = DateUtils.addSeconds(Calendar.getInstance().getTime(), expireSeconds).getTime() + "," + uniqueId;
        boolean ifAbsent = this.setIfAbsent(lockKey, lockValue, expireSeconds);
        if (ifAbsent) {
            return uniqueId;
        } else {
            String currentValue = (String)this.stringRedisTemplate.opsForValue().get(lockKey);
            if (StringUtils.isNotBlank(currentValue) && Calendar.getInstance().getTimeInMillis() > NumberUtils.toLong(currentValue.split(",")[0])) {
                this.stringRedisTemplate.delete(lockKey);
                ifAbsent = this.setIfAbsent(lockKey, lockValue, expireSeconds);
                if (ifAbsent) {
                    return uniqueId;
                }
            }

            return null;
        }
    }

    private boolean setIfAbsent(String lockKey, String lockValue, int expireSeconds) {
        Boolean ifAbsent = this.stringRedisTemplate.opsForValue().setIfAbsent(lockKey, lockValue);
        if (Boolean.TRUE.equals(ifAbsent)) {
            this.stringRedisTemplate.expire(lockKey, (long)expireSeconds, TimeUnit.SECONDS);
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Business lock ：{}", lockKey);
            }
        }

        return ifAbsent;
    }
}
